package com.dongrj.framework.starter.log.dingding.chain;

import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiRobotSendRequest;
import com.dongrj.framework.core.utils.AppUtils;
import com.dongrj.framework.core.utils.JsonUtils;
import com.dongrj.framework.core.utils.StringUtils;
import com.dongrj.framework.starter.log.dingding.DingTalkMsg;
import com.dongrj.framework.starter.log.dingding.MessageType;
import com.google.common.collect.Maps;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.codec.binary.Base64;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * @author dongrongjun
 * @date 2020/12/02
 */
@Slf4j
public abstract class AbstractRobot {

    private AbstractRobot next;

    public AbstractRobot next(AbstractRobot next) {
        this.next = next;
        return next;
    }

    public void send(DingTalkMsg dingTalkMsg) {
        if (check(dingTalkMsg)) {
            setExtend(dingTalkMsg);
            before(dingTalkMsg);
            action(dingTalkMsg);
        } else {
            if (next != null) {
                next.send(dingTalkMsg);
            }
        }
    }


    private void setExtend(DingTalkMsg dingTalkMsg) {
        if (MessageType.Original.equals(dingTalkMsg.getMsgType())) {
            return;
        }
        if (dingTalkMsg.getSendRequest() != null) {
            return;
        }
        Map<String, String> map = Maps.newHashMapWithExpectedSize(4);
        map.put("appId", AppUtils.getAppId());
        map.put("host", AppUtils.getLocalIP());
        map.put("env", "xxx");
        map.put("message", dingTalkMsg.getMessage());
        String msg = JsonUtils.toJson(map);
        dingTalkMsg.setMessage(msg);
    }


    /**
     * 校验操作
     *
     * @param dingDing 消息
     */
    protected abstract boolean check(DingTalkMsg dingDing);

    /**
     * 原始WebHook
     */
    public abstract String getWebHook();

    /**
     * 原始密钥
     */
    public abstract String getSecret();

    public void before(DingTalkMsg dingTalkMsg) {

    }

    /**
     * 请求操作
     *
     * @param dingTalkMsg 消息内容
     */
    private void action(DingTalkMsg dingTalkMsg) {
        OapiRobotSendRequest sendRequest = dingTalkMsg.getSendRequest();
        if (sendRequest != null) {
            sendMsg(sendRequest);
            return;
        }
        String message = dingTalkMsg.getMessage();
        if (StringUtils.isEmpty(message)) {
            log.info("action.content.null={}", dingTalkMsg);
            return;
        }
        //1. 设置消息类型
        OapiRobotSendRequest request = new OapiRobotSendRequest();
        request.setMsgtype("text");

        //2. 设置消息内容
        OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text();
        text.setContent(message);
        request.setText(text);

        // 设置消息是否At其他人
        OapiRobotSendRequest.At at = new OapiRobotSendRequest.At();
        at.setIsAtAll("true".equals(dingTalkMsg.getIsAtAll()));
        request.setAt(dingTalkMsg.getAtMobiles());
        sendMsg(request);
    }


    private void sendMsg(OapiRobotSendRequest request) {
        String url = getRealWebHook();
        DingTalkClient client = new DefaultDingTalkClient(url);
        try {
            client.execute(request);
        } catch (ApiException e) {
            log.info("钉钉发送异常:{}", e.getMessage());
        }
    }


    /**
     * 组装真实的WebHook
     */
    private String getRealWebHook() {
        long timestamp = System.currentTimeMillis();
        String robotSign;
        try {
            robotSign = getRobotSign(timestamp, getSecret());
        } catch (Exception e) {
            log.info("getUrl.e={}", e);
            throw new RuntimeException("获取WebHook异常!");
        }
        return getWebHook() + "&timestamp=" + timestamp + "&sign=" + robotSign;
    }

    private String getRobotSign(long timestamp, String secret) throws Exception {
        String stringToSign = timestamp + "\n" + secret;
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
        byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
        return URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
    }
}
